#include <network\connectionThread.h>
#include <commands\command.h>
#include <commands\commandFactory.h>
#include <app\states\connectionState.h>

using std::cout;
using std::endl;

void 
connectionThread::receiveBytes(void *buffer, StreamSocket &socket, unsigned int count) {
  
  unsigned char *bytes = new unsigned char[count];
  int br = 0;

  memset(bytes, 0, count);

  while (br < count && socket.available()) {
    br += socket.receiveBytes(&bytes[br], count - br);
  }

  memcpy(buffer, bytes, count);

  delete bytes;
}

void 
connectionThread::addCommand(command *cmd) {
  commands_mutex.lock();

   commands.push_back(cmd);

  commands_mutex.unlock();
}

void 
connectionThread::run() {

  bool verified = false;

  StreamSocket socket;
  try {
    socket.connect(SocketAddress("localhost:9000"));

    while (!state.isFinishRequested()) {

      unsigned short commandId = 0;
      receiveBytes(&commandId, socket, sizeof(unsigned short));

      // decode received commands from server
      if (commandId != 0) {
        command *cmd = commandFactory::instance().createCommand(commandId, this);
        if (cmd) {
          cmd->decode(socket);
          delete cmd;
        }
      }

      // execute commands to server
      command *cmd;
      commands_mutex.lock();
      if (!commands.empty()) {
        cmd = commands.front();
        commands_mutex.unlock();
        commands.erase(commands.begin());
        cmd->execute(socket);
        delete cmd;
      }
      else {
        commands_mutex.unlock();
      }

      Sleep(1);
    }
  }
  catch (Exception& exc) { 
    cout << exc.what() << endl;
  } 

  try {
    command *cmd = commandFactory::instance().createCommand(CLIENT_SEND_EXIT, this);
    if (cmd) {
      cmd->execute(socket);
      delete cmd;
    }
  }
  catch (Exception& exc) { 
    cout << exc.what() << endl;
  } 
}

connectionThread::~connectionThread() {
  state.requestFinish();
}